<?php
if (! defined('IN_SITE')) {
	exit('invalid request');
}

include_once ROOT_PATH . 'include/logger.php';

/**
 * 后台任务基础类。
 */
abstract class TaskBase {
	/**
	 * 扩展类只需要重载此方法，完成实际的处理逻辑。
	 */
	abstract protected function onRun();

	public function __construct()
	{
		global $argv;
		$filename = basename($argv[0]);
		if (strEndsWith($filename, '.task.php')) {
			$filename = substr($filename, 0, -9);
		}
		$this->myname = $filename;
	}

	public function run()
	{
		if (!$this->enter()) {
			CLogger::log('task', "[{$this->myname}] busy, skipped.");
			exit();
		}

		// 程序结束时做记录，便于检查异常错误
		register_shutdown_function(array($this, 'my_shutdown_func'));

		CLogger::log('task', "[{$this->myname}] enter()");
		$this->onRun();
		$this->leave();
		CLogger::log('task', "[{$this->myname}] leave()");
	}

	public function my_shutdown_func()
	{
		$error = error_get_last();
		if ($error) {
			CLogger::log('task', "[{$this->myname}] 程序结束，最后一条报错信息: " . var_export($error, true));
		}
	}

	protected function enter()
	{
		// 加锁避免重入
		$this->lockfile = "{$GLOBALS['config']['log_path']}{$this->myname}.task.lock";
 		$this->lock = fopen($this->lockfile, 'w+');
 		if (!$this->lock) return false;
 		if (!flock($this->lock, LOCK_EX | LOCK_NB)) {
			fclose($this->lock);
			return false;
		}
		fwrite($this->lock, getmypid());
		fflush($this->lock);
		return true;
	}

	protected function leave()
	{
		// 解锁退出
		fclose($this->lock);
		unlink($this->lockfile);
	}

	/**
	 * 启动执行一个任务。
	 * @param array $task
	 * @return boolean 如果指定的任务程序代码不存在，则返回 false，否则返回 true。
	 */
	static public function runTask($task)
	{
		$tasks_dir = $GLOBALS['config']['tasks_path'];

		$task_file = "{$tasks_dir}{$task['code']}.task.php";
		$task_php = realpath($task_file);
		if ($task_php === false) {
			CLogger::log('task', "[cron] 任务程序文件不存在: \"{$task_file}\"");
			return false;
		}

		// 通过外部命令启动相应的处理程序
		if (isDebugStage()) {
			$php = PHP_BINARY; // PHP >= 5.4
			$php_ini = php_ini_loaded_file();
			$cmd = "start \"{$task['code']}\" /B \"{$php}\" -c \"{$php_ini}\" -f \"{$task_php}\"";
			CLogger::log('task', "[cron] runTask: {$task['code']} - {$task['title']}\r\ncmd：{$cmd}");
			pclose(popen($cmd, 'r'));
		} else {
			$php = 'php';
			$php_ini = php_ini_loaded_file();
			$cmd = "\"{$php}\" -c \"{$php_ini}\" -f \"{$task_php}\" 1>/dev/null 2>/dev/null &";
			CLogger::log('task', "[cron] runTask: {$task['code']} - {$task['title']}\r\ncmd：{$cmd}");
			exec($cmd);
		}

		return true;
	}
}
